#ifndef XMLRPC_PARSER_H
#define XMLRPC_PARSER_H

#include <xml/contenthandler.h>

namespace XmlRpc
{

class CContentHandlerState;

class CResponseContentHandler : public CBase, public Xml::MContentHandler
	{
public:
	IMPORT_C CResponseContentHandler(CXmlRpcResult& aResult) : iState(NULL), iResult(aResult) {}
	IMPORT_C ~CResponseContentHandler();
	
	IMPORT_C virtual void OnStartDocumentL(const Xml::RDocumentParameters& aDocParam, TInt aErrorCode);
	IMPORT_C virtual void OnEndDocumentL(TInt aErrorCode);

	IMPORT_C virtual void OnStartElementL(const Xml::RTagInfo& aElement, const Xml::RAttributeArray& aAttributes, TInt aErrorCode);
	IMPORT_C virtual void OnEndElementL(const Xml::RTagInfo& aElement, TInt aErrorCode);

	IMPORT_C virtual void OnContentL(const TDesC8& aBytes, TInt aErrorCode);

	IMPORT_C virtual void OnError(TInt aErrorCode);


	// unimplemented
	virtual void OnStartPrefixMappingL(const RString&, const RString&, TInt) {}
	virtual void OnEndPrefixMappingL(const RString&, TInt) {}

	virtual void OnIgnorableWhiteSpaceL(const TDesC8&, TInt) {}
	virtual void OnSkippedEntityL(const RString&, TInt) {}

	virtual void OnProcessingInstructionL(const TDesC8&, const TDesC8&, TInt) {}
	virtual TAny* GetExtendedInterface(const TInt32) { return NULL;}

	CContentHandlerState* iState;
private:
	CXmlRpcResult& iResult;
	};

class CXmlRpcResult;
class CValue;

class CContentHandlerState : public CBase
	{
public:
	CContentHandlerState(CResponseContentHandler* aContentHandler, CContentHandlerState* aParentState, CXmlRpcResult& aResult) : iResult(aResult), iParentState(aParentState), iContentHandler(aContentHandler) {}
	virtual ~CContentHandlerState()
		{
		if (iParentState)
			{
			delete iParentState;
			iParentState = NULL;
			}
		}
	
	virtual void InputL(const Xml::RTagInfo&, TBool = EFalse) {}
	virtual void InputL(const TDesC8&) {}

	// called by child states
	virtual void FoundValueL(CValue*) { ASSERT(0); } // should only be called on states that explicitly support it
	void Finish()
		{
		ASSERT(iParentState);
		iContentHandler->iState = iParentState;
		iParentState = NULL;
		delete this;
		}
	
	void EnterState(CContentHandlerState* aState)
		{
		iContentHandler->iState = aState;
		}

	CResponseContentHandler* ContentHandler() {
		return iContentHandler;
	}
protected:
	CXmlRpcResult& iResult;
	/** if a state has a parent state at time of destruction, then it is up to that state to
		destroy the parent state. parent state should be nulled once it has been reinstated by
		Finish() for this very reason. Last existing state should be deleted by Content Handler.
		In a properly formatted xml document, this should be the Init state
	*/
	CContentHandlerState *iParentState;

private:
	CResponseContentHandler *iContentHandler;
	};

NONSHARABLE_CLASS(CInitState) : public CContentHandlerState
	{
public:
	CInitState(CResponseContentHandler* aContentHandler, CContentHandlerState* aParentState, CXmlRpcResult& aResult) : CContentHandlerState(aContentHandler, aParentState, aResult) {}
	void InputL(const Xml::RTagInfo& aElement, TBool aEndTag = EFalse);
	};


_LIT8(KMethodResponseTag, "methodResponse");	
NONSHARABLE_CLASS(CMethodResponseState) : public CContentHandlerState
	{
public:
	CMethodResponseState(CResponseContentHandler* aContentHandler, CContentHandlerState* aParentState, CXmlRpcResult& aResult) : CContentHandlerState(aContentHandler, aParentState, aResult) {}
	void InputL(const Xml::RTagInfo& aElement, TBool aEndTag = EFalse);
	};

_LIT8(KFaultTag, "fault");
NONSHARABLE_CLASS(CFaultState) : public CContentHandlerState
	{
public:
	CFaultState(CResponseContentHandler* aContentHandler, CContentHandlerState* aParentState, CXmlRpcResult& aResult) : CContentHandlerState(aContentHandler, aParentState, aResult) {}
	void InputL(const Xml::RTagInfo& aElement, TBool aEndTag = EFalse);
	virtual void FoundValueL(CValue* aValue);
	};

_LIT8(KParamsTag, "params");
NONSHARABLE_CLASS(CParamsState) : public CContentHandlerState
	{
public:
	CParamsState(CResponseContentHandler* aContentHandler, CContentHandlerState* aParentState, CXmlRpcResult& aResult) : CContentHandlerState(aContentHandler, aParentState, aResult) {}
	void InputL(const Xml::RTagInfo& aElement, TBool aEndTag = EFalse);
	virtual void FoundValueL(CValue* aValue);

	};

_LIT8(KParamTag, "param");
NONSHARABLE_CLASS(CParamState) : public CContentHandlerState
	{
public:
	CParamState(CResponseContentHandler* aContentHandler, CContentHandlerState* aParentState, CXmlRpcResult& aResult) : CContentHandlerState(aContentHandler, aParentState, aResult) {}
	void InputL(const Xml::RTagInfo& aElement, TBool aEndTag = EFalse);
	virtual void FoundValueL(CValue* aValue);
	};

_LIT8(KValueTag, "value");
NONSHARABLE_CLASS(CValueState) : public CContentHandlerState
	{
public:
	CValueState(CResponseContentHandler* aContentHandler, CContentHandlerState* aParentState, CXmlRpcResult& aResult) : CContentHandlerState(aContentHandler, aParentState, aResult) {}
	~CValueState();
	void InputL(const Xml::RTagInfo& aElement, TBool aEndTag = EFalse);
	void InputL(const TDesC8& aBytes);
	virtual void FoundValueL(CValue* aValue);
	
protected:
	/**
	 * class only owns this until it passed off to parent through FoundValue;
	 * should be nulled at that point, therefore, if not null, destroy
	 */
	CValue* iValue;
	RBuf8 iBuf;
	};


_LIT8(KIntTag1, "int");
_LIT8(KIntTag2, "i4");
NONSHARABLE_CLASS(CIntState) : public CValueState
	{
public:
	CIntState(CResponseContentHandler* aContentHandler, CContentHandlerState* aParentState, CXmlRpcResult& aResult) : CValueState(aContentHandler, aParentState, aResult) {}
	virtual void InputL(const Xml::RTagInfo& aElement, TBool aEndTag = EFalse);
	};

_LIT8(KBooleanTag, "boolean");
NONSHARABLE_CLASS(CBooleanState) : public CValueState
	{
public:
	CBooleanState(CResponseContentHandler* aContentHandler, CContentHandlerState* aParentState, CXmlRpcResult& aResult) : CValueState(aContentHandler, aParentState, aResult) {}
	virtual void InputL(const Xml::RTagInfo& aElement, TBool aEndTag = EFalse);
	};

_LIT8(KDoubleTag, "double");
NONSHARABLE_CLASS(CDoubleState) : public CValueState
	{
public:
	CDoubleState(CResponseContentHandler* aContentHandler, CContentHandlerState* aParentState, CXmlRpcResult& aResult) : CValueState(aContentHandler, aParentState, aResult) {}
	virtual void InputL(const Xml::RTagInfo& aElement, TBool aEndTag = EFalse);
	};

_LIT8(KDateTimeTag, "dateTime.iso8601");
NONSHARABLE_CLASS(CDateTimeState) : public CValueState
	{
public:
	CDateTimeState(CResponseContentHandler* aContentHandler, CContentHandlerState* aParentState, CXmlRpcResult& aResult) : CValueState(aContentHandler, aParentState, aResult) {}
	virtual void InputL(const Xml::RTagInfo& aElement, TBool aEndTag = EFalse);
	};

_LIT8(KStringTag, "string");
NONSHARABLE_CLASS(CStringState) : public CValueState
	{
public:
	CStringState(CResponseContentHandler* aContentHandler, CContentHandlerState* aParentState, CXmlRpcResult& aResult) : CValueState(aContentHandler, aParentState, aResult) {}
	virtual void InputL(const Xml::RTagInfo& aElement, TBool aEndTag = EFalse);
	};

_LIT8(KBase64Tag, "base64");
NONSHARABLE_CLASS(CBase64State) : public CValueState
	{
public:
	CBase64State(CResponseContentHandler* aContentHandler, CContentHandlerState* aParentState, CXmlRpcResult& aResult) : CValueState(aContentHandler, aParentState, aResult) {}
	virtual void InputL(const Xml::RTagInfo& aElement, TBool aEndTag = EFalse);
	};

_LIT8(KStructTag, "struct");
_LIT8(KMemberTag, "member");
_LIT8(KNameTag, "name");
NONSHARABLE_CLASS(CStructState) : public CValueState
	{
public:
	
	CStructState(CResponseContentHandler* aContentHandler, CContentHandlerState* aParentState, CXmlRpcResult& aResult) : CValueState(aContentHandler, aParentState, aResult) {}
	virtual void InputL(const Xml::RTagInfo& aElement, TBool aEndTag = EFalse);
	virtual void InputL(const TDesC8& aBytes);
	virtual void FoundValueL(CValue* aValue);
	void FoundMemberL(const TDesC8& aKey, CValue* aValue);
private:
	CStruct* GetStructL();
	};

NONSHARABLE_CLASS(CMemberState) : public CValueState
	{
public:
	CMemberState(CResponseContentHandler* aContentHandler, CContentHandlerState* aParentState, CXmlRpcResult& aResult) : CValueState(aContentHandler, aParentState, aResult)
		{}
	~CMemberState();
	virtual void InputL(const Xml::RTagInfo& aElement, TBool aEndTag = EFalse);
	virtual void InputL(const TDesC8& aBytes);
	virtual void FoundNameL(const TDesC8& aName);
	virtual void FoundValueL(CValue* aValue);

private:
	RBuf8 iName;
	};

NONSHARABLE_CLASS(CNameState) : public CValueState
	{
public:	
	CNameState(CResponseContentHandler* aContentHandler, CContentHandlerState* aParentState, CXmlRpcResult& aResult) : CValueState(aContentHandler, aParentState, aResult) {}
	virtual void InputL(const Xml::RTagInfo& aElement, TBool aEndTag = EFalse);
	};

_LIT8(KArrayTag, "array");
_LIT8(KDataTag, "data");
NONSHARABLE_CLASS(CArrayState) : public CValueState
	{
public:
	CArrayState(CResponseContentHandler* aContentHandler, CContentHandlerState* aParentState, CXmlRpcResult& aResult) : CValueState(aContentHandler, aParentState, aResult) {}
	virtual void InputL(const Xml::RTagInfo& aElement, TBool aEndTag = EFalse);
	virtual void InputL(const TDesC8& aBytes);
	virtual void FoundValueL(CValue* aValue);

private:
	CArray* GetArrayL();
	};

NONSHARABLE_CLASS(CDataState) : public CValueState
	{
public:	
	CDataState(CResponseContentHandler* aContentHandler, CContentHandlerState* aParentState, CXmlRpcResult& aResult) : CValueState(aContentHandler, aParentState, aResult) {}
	virtual void InputL(const Xml::RTagInfo& aElement, TBool aEndTag = EFalse);
	};
}

#endif

